package com.yc.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yc.annotation.Query;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

@Slf4j
public class QueryHelpPlus {

    public static <R, Q> QueryWrapper<R> getPredicate(Q query) {
        QueryWrapper<R> queryWrapper = new QueryWrapper<>();
        if (query == null) {
            return queryWrapper;
        }
        try {
            List<Field> fields = getAllFields(query.getClass(), new ArrayList<>());
            for (Field field : fields) {
                boolean accessible = field.isAccessible();
                field.setAccessible(true);
                Query q = field.getAnnotation(Query.class);
                if (q != null) {
                    String propName = q.propName();
                    String blurry = q.blurry();
                    String attributeName = isBlank(propName) ? field.getName() : propName;
                    attributeName = humpToUnderline(attributeName);
                    Object val = field.get(query);
                    if (ObjectUtil.isNull(val) || "".equals(val)) {
                        continue;
                    }
                    // 模糊多字段
                    if (ObjectUtil.isNotEmpty(blurry)) {
                        String[] blurrys = blurry.split(",");
                        queryWrapper.and(wrapper -> {
                            for (String s : blurrys) {
                                String column = humpToUnderline(s);
                                wrapper.or();
                                wrapper.like(column, val.toString());
                            }
                        });
                        continue;
                    }
                    String finalAttributeName = attributeName;
                    switch (q.value()) {
                        case EQUAL -> queryWrapper.eq(attributeName, val);
                        case GREATER_THAN -> queryWrapper.ge(finalAttributeName, val);
                        case GREATER_THAN_NQ -> queryWrapper.gt(finalAttributeName, val);
                        case LESS_THAN -> queryWrapper.le(finalAttributeName, val);
                        case LESS_THAN_NQ -> queryWrapper.lt(finalAttributeName, val);
                        case INNER_LIKE -> queryWrapper.like(finalAttributeName, val);
                        case LEFT_LIKE -> queryWrapper.likeLeft(finalAttributeName, val);
                        case RIGHT_LIKE -> queryWrapper.likeRight(finalAttributeName, val);
                        case IN -> {
                            List<Long> in = objToList(val, Long.class);
                            if (CollUtil.isNotEmpty(in)) {
                                queryWrapper.in(finalAttributeName, in);
                            }
                        }
                        case NOT_EQUAL -> queryWrapper.ne(finalAttributeName, val);
                        case NOT_NULL -> queryWrapper.isNotNull(finalAttributeName);
                        case BETWEEN -> {
                            List<Object> between = objToList(val, Object.class);
                            queryWrapper.between(finalAttributeName, between.get(0), between.get(1));
                        }
                        case UNIX_TIMESTAMP -> {
                            List<Object> UNIX_TIMESTAMP = objToList(val, Object.class);
                            if (!UNIX_TIMESTAMP.isEmpty()) {
                                SimpleDateFormat fm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                Date time1 = fm.parse(UNIX_TIMESTAMP.get(0).toString());
                                Date time2 = fm.parse(UNIX_TIMESTAMP.get(1).toString());
                                queryWrapper.between(finalAttributeName, time1, time2);
                            }
                        }
                        default -> {
                        }
                    }
                }
                field.setAccessible(accessible);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return queryWrapper;
    }


    private static boolean isBlank(final CharSequence cs) {
        int strLen;
        if (cs == null || (strLen = cs.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if (!Character.isWhitespace(cs.charAt(i))) {
                return false;
            }
        }
        return true;
    }

    private static List<Field> getAllFields(Class<?> clazz, List<Field> fields) {
        if (clazz != null) {
            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
            getAllFields(clazz.getSuperclass(), fields);
        }
        return fields;
    }

    private static <T> List<T> objToList(Object obj, Class<T> cla) {
        List<T> list = new ArrayList<>();
        if (obj instanceof ArrayList<?>) {
            for (Object o : (List<?>) obj) {
                list.add(cla.cast(o));
            }
            return list;
        }
        return null;
    }

    /***
     * 驼峰命名转为下划线命名
     *
     * @param para
     *        驼峰命名的字符串
     */

    public static String humpToUnderline(String para) {
        StringBuilder sb = new StringBuilder(para);
        int temp = 0;//定位
        if (!para.contains("_")) {
            for (int i = 0; i < para.length(); i++) {
                if (Character.isUpperCase(para.charAt(i))) {
                    sb.insert(i + temp, "_");
                    temp += 1;
                }
            }
        }
        return sb.toString();
    }

}
